#include "esp_camera.h"
#include <WiFi.h>

// ===========================
// 在 board_config.h 中选择摄像头型号
// ===========================
#include "board_config.h"

// ===========================
// 用户配置文件 - 所有默认配置集中在此
// ===========================
#include "user_config.h"

// WiFi凭据
const char *ssid = WIFI_SSID;
const char *password = WIFI_PASSWORD;

void startCameraServer();
void setupLedFlash();

void setup() {
  Serial.begin(SERIAL_BAUDRATE);
  Serial.setDebugOutput(SERIAL_DEBUG_OUTPUT);
  Serial.println();

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = CAM_XCLK_FREQ;
  config.frame_size = CAM_FRAME_SIZE;
  config.pixel_format = PIXFORMAT_JPEG;  // 用于流媒体
  //config.pixel_format = PIXFORMAT_RGB565; // 用于人脸检测/识别
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = CAM_JPEG_QUALITY;
  config.fb_count = CAM_FB_COUNT;

  // 如果存在PSRAM IC，使用UXGA分辨率和更高的JPEG质量初始化
  //                      以获得更大的预分配帧缓冲区。
  if (config.pixel_format == PIXFORMAT_JPEG) {
    if (psramFound()) {
      config.jpeg_quality = CAM_PSRAM_JPEG_QUALITY;
      config.fb_count = CAM_PSRAM_FB_COUNT;
      config.grab_mode = CAMERA_GRAB_LATEST;
    } else {
      // 当PSRAM不可用时，限制帧大小
      config.frame_size = CAM_NO_PSRAM_FRAME_SIZE;
      config.fb_location = CAMERA_FB_IN_DRAM;
    }
  } else {
    // 人脸检测/识别的最佳选项
    config.frame_size = FACE_DETECT_FRAME_SIZE;
#if CONFIG_IDF_TARGET_ESP32S3
    config.fb_count = CAM_PSRAM_FB_COUNT;
#endif
  }

#if defined(CAMERA_MODEL_ESP_EYE)
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
#endif

  // 摄像头初始化
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("摄像头初始化失败，错误代码 0x%x", err);
    return;
  }

  sensor_t *s = esp_camera_sensor_get();
  // 初始传感器垂直翻转且颜色略微饱和
  if (s->id.PID == OV2640_PID) {
    s->set_vflip(s, OV2640_VFLIP);           // 垂直翻转
    s->set_brightness(s, OV2640_BRIGHTNESS); // 亮度调整
    s->set_saturation(s, OV2640_SATURATION); // 饱和度调整
  }
  // 降低帧大小以获得更高的初始帧率
  if (config.pixel_format == PIXFORMAT_JPEG) {
    s->set_framesize(s, CAM_RUNTIME_FRAME_SIZE);
  }

#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
  s->set_vflip(s, 1);
  s->set_hmirror(s, 1);
#endif

#if defined(CAMERA_MODEL_ESP32S3_EYE)
  s->set_vflip(s, 1);
#endif

// 如果在 camera_pins.h 中定义了LED引脚，则设置LED闪光灯
#if defined(LED_GPIO_NUM)
  setupLedFlash();
#endif

  WiFi.begin(ssid, password);
  WiFi.setSleep(!WIFI_SLEEP_DISABLE);

  Serial.print("正在连接WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi连接成功");

  startCameraServer();

  Serial.print("摄像头就绪！请访问 'http://");
  Serial.print(WiFi.localIP());
  Serial.println("' 进行连接");
}

void loop() {
  // 无操作。所有任务由Web服务器在另一个任务中完成
  delay(LOOP_DELAY);
}
